package com.pig4cloud.pig.common.core.util;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Title null.java
 * @Package com.pig4cloud.pigx.common.core.util
 * @Author 马嘉祺
 * @Date 2021/6/23 16:58
 * @Description
 */
public final class EBeanUtil {


	private EBeanUtil() {
	}

	/**
	 * 获取Class Field映射
	 *
	 * @param clazz
	 * @return
	 */
	public static Map<String, Field> getFieldMap(Class<?> clazz) {
		return Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toMap(Field::getName, e -> e));
	}

	/**
	 * 将泛型为String的Map转换为对象
	 *
	 * @param source
	 * @param clazz
	 * @param valueOfs
	 * @param <T>
	 * @return
	 * @throws Exception
	 */
	@SafeVarargs
	public static <T> T stringMapToObject(Map<String, String> source, Class<T> clazz, BiFunction<Class<?>, String, Object>... valueOfs) throws Exception {
		return stringMapToObject(source, clazz, getFieldMap(clazz), valueOfs);
	}

	/**
	 * 将泛型为String的Map转换为对象
	 *
	 * @param source
	 * @param clazz
	 * @param fieldMap
	 * @param valueOfs
	 * @param <T>
	 * @return
	 * @throws Exception
	 */
	@SafeVarargs
	public static <T> T stringMapToObject(Map<String, String> source, Class<T> clazz, Map<String, Field> fieldMap, BiFunction<Class<?>, String, Object>... valueOfs) throws Exception {
		T object = clazz.newInstance();
		for (Map.Entry<String, String> bean : source.entrySet()) {
			Field field = fieldMap.get(bean.getKey());
			field.setAccessible(true);
			Class<?> type = field.getType();
			String value = bean.getValue();
			if (type == String.class) {
				field.set(object, value);
			} else if (type == Long.class) {
				field.set(object, Long.valueOf(value));
			} else if (type == Double.class) {
				field.set(object, Double.valueOf(value));
			} else if (type == Integer.class) {
				field.set(object, Integer.valueOf(value));
			} else if (type == Float.class) {
				field.set(object, Float.valueOf(value));
			} else if (type == Short.class) {
				field.set(object, Short.valueOf(value));
			} else if (type == Byte.class) {
				field.set(object, Byte.valueOf(value));
			} else if (type == BigDecimal.class) {
				field.set(object, new BigDecimal(value));
			} else {
				Object value1 = Optional.ofNullable(valueOfs).map(e -> Arrays.stream(e).map(f -> f.apply(type, value)).filter(Objects::nonNull).findFirst()).flatMap(e -> e).orElse(null);
				if (null != value1) {
					field.set(object, value1);
				}
			}
		}
		return object;
	}

	/**
	 * 将对象转换为泛型String的Map
	 *
	 * @param object
	 * @param toStrings
	 * @param <T>
	 * @return
	 * @throws Exception
	 */
	@SafeVarargs
	public static <T> Map<String, String> objectToStringMap(T object, Function<Object, String>... toStrings) throws Exception {
		Map<String, String> result = new HashMap<>();
		Field[] fields = object.getClass().getDeclaredFields();

		for (Field field : fields) {
			field.setAccessible(true);
			Object value = field.get(object);
			if (null == value) {
				continue;
			}
			if (value instanceof String) {
				if (StringUtils.isNotEmpty((String) value)) {
					result.put(field.getName(), (String) value);
				}
				continue;
			}
			String str = Optional.ofNullable(toStrings).map(e -> Arrays.stream(e).map(f -> f.apply(value)).filter(Objects::nonNull).findFirst()).flatMap(e -> e).orElse(null);
			if (null != str) {
				result.put(field.getName(), str);
			} else {
				result.put(field.getName(), value.toString());
			}
		}
		return result;
	}

}
